package org.shiro.config;

import cn.hutool.core.collection.CollectionUtil;
import org.shiro.utils.ShiroUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static cn.hutool.core.util.StrUtil.EMPTY;

/**
 * 系统程序初始化服务
 *
 * @author LiKun
 * @date 2021/11/3 15:47
 */
@Component
public class ApplicationInitialize implements ApplicationRunner {
    private static final Logger logger = LoggerFactory.getLogger(ApplicationInitialize.class);

    private final Map<String, Boolean> approveContainer = new HashMap<>();
    private final List<Class> shiroRequiresAuthenticationAnnotations = ShiroUtil.getRequiresAuthenticationAnnotations();

    @Resource
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    /**
     * 执行系统初始化方法
     *
     * @param args 相关参数
     */
    @Override
    public void run(ApplicationArguments args) {
        logger.info("开始加载请求权限数据");

        requestMappingHandlerMapping.getHandlerMethods().forEach((key, value) ->
                approveContainer.put(key.getPatternsCondition().getPatterns().stream().findFirst().orElse(EMPTY),
                        this.judgeRequiredCertification(value.getMethod())));

        logger.info("完成加载请求权限数据");
    }

    /**
     * 判断给定的路径是否需要用户认证
     *
     * @param path 网络路径
     *
     * @return 校验结果
     */
    public boolean judgePathRequiredAuthentication(String path) {
        return CollectionUtil.isNotEmpty(approveContainer);
    }


    /*-----------------------------------------------private method---------------------------------------------------*/


    /**
     * 判断给定的方法是否需要认证
     *
     * @param method 给定的方法
     *
     * @return 判断结果
     */
    private Boolean judgeRequiredCertification(Method method) {
        return Arrays.stream(method.getAnnotations())
                .anyMatch(annotation -> shiroRequiresAuthenticationAnnotations.contains(annotation.annotationType()));
    }
}
